//
//  NetWorkRequest.m
//  OCDemo
//
//  Created by zhumuzhi on 2021/3/18.
//

#import "NetWorkRequest.h"
#import "NetworkStateUtils.h"


/**
 * 请求超时时间
 */
static const NSTimeInterval kTimeoutInterval = 60.0;

@interface NetWorkRequest ()

@property (nonatomic, strong) NSMutableArray        *requests;
@property (nonatomic, strong) NSMutableArray        *requestInfo;
@property (nonatomic, strong) NSURLSessionDataTask  *bodyTask;

@end

@implementation NetWorkRequest

#pragma mark - 单例方法

+ (instancetype)sharedNetworkRequest {
    static NetWorkRequest *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if(!instance) {
            instance = [[self alloc] init];
        }
    });
    return instance;
}

#pragma mark - SessionManager配置

- (AFHTTPSessionManager *)getSessionManger {
    AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager];
    AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
    serializer.removesKeysWithNullValues = YES;
    serializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/javascript",@"text/json",@"text/plain",@"text/html",@"application/zip",@"application/x-www-form-urlencoded",@"multipart/form-data", nil];
    sessionManager.responseSerializer = serializer;
    
    // AFSSLPinningModeCertificate 使用证书验证模式
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
    // allowInvalidCertificates 是否允许无效证书（也就是自建的证书），默认为NO
    // 如果需要验证自建证书(无效证书)，需要设置为YES
    securityPolicy.allowInvalidCertificates = YES;
    //validatesDomainName 是否需要验证域名，默认为YES；
    //假如证书的域名与你请求的域名不一致，需把该项设置为NO；如设成NO的话，即服务器使用其他可信任机构颁发的证书，也可以建立连接，这个非常危险，建议打开。
    //置为NO，主要用于这种情况：客户端请求的是子域名，而证书上的是另外一个域名。因为SSL证书上的域名是独立的，假如证书上注册的域名是www.google.com，那么mail.google.com是无法验证通过的；当然，有钱可以注册通配符的域名*.google.com，但这个还是比较贵的。
    //如置为NO，建议自己添加对应域名的校验逻辑。
    securityPolicy.validatesDomainName = NO;
    sessionManager.securityPolicy = securityPolicy;
    
    return sessionManager;
}

#pragma mark - Get请求

- (NSURLSessionDataTask *)getRequest:(NSString *)url
                          parameters:(NSDictionary *)parameter
                        successBlock:(NetworkRequestSuccessBlock)successBlock
                        failureBlock:(NetworkRequestFailureBlock)failureBlock {
    
    WS(weakSelf)
    AFHTTPSessionManager *sessionManager = [self getSessionManger];
    sessionManager.requestSerializer.timeoutInterval = kTimeoutInterval;
    NSDictionary *parameters = [[RequestParams share] parameterSortWithDictionary:parameter];
    NSLog(@"\n==>>>>url==%@\nparameters==%@",url,[parameters mj_JSONString]);
    NSURLSessionDataTask *dataTask = [sessionManager GET:url  parameters:parameters headers:nil progress:^(NSProgress * _Nonnull downloadProgress) {}
    success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        // 将请求从请求数组中移除
        [weakSelf.requests removeObject:task];

        // 先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        if (successBlock) {
            successBlock(responseObject,infoModel);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        // 将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        // 先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        if (failureBlock) {
            failureBlock(error,infoModel);
        }
    }];
    
    // 将请求加入请求数组中
    [self.requests addObject:dataTask];
    
    // 由于ios7系统给NSURLSessionTask添加类目属性会崩溃，所以改用此方法
    [self addToArrayWithNewTask:dataTask url:url info:parameter];
    
    return dataTask;
    
}

#pragma mark - Post请求 参数

- (NSURLSessionDataTask *)postRequest:(NSString *)url
                           parameters:(NSDictionary *)parameter
                         successBlock:(NetworkRequestSuccessBlock)successBlock
                         failureBlock:(NetworkRequestFailureBlock)failureBlock {
    
    WS(weakSelf)
    AFHTTPSessionManager *sessionManager = [self getSessionManger];
    sessionManager.requestSerializer.timeoutInterval = kTimeoutInterval;
    // 公参配置逻辑
    NSDictionary *parameters = [[RequestParams share] parameterSortWithDictionary:parameter];
    NSLog(@"\n==>>>>url==%@\nparameters==%@",url,[parameters mj_JSONString]);
    NSURLSessionDataTask *dataTask = [sessionManager POST:url parameters:parameters headers:nil progress:^(NSProgress *uploadProgress) {}
    success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
        //：将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        
        //：先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];

        if (successBlock) {
            successBlock(responseObject,infoModel);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"error==%@", error);
        NSLog(@"error.code==%@,description==%@",@(error.code),error.localizedDescription);
        //：将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        //：先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        if (failureBlock) {
            failureBlock(error,infoModel);
        }
    }];
    
    //：将请求加入请求数组中
    [self.requests addObject:dataTask];

    @try {
        // ：由于ios7系统给NSURLSessionTask添加类目属性会崩溃，所以改用此方法
        [self addToArrayWithNewTask:dataTask url:url info:parameter];
    } @catch (NSException *exception) {
//        [kKeyWindow makeToast:exception.description];
    } @finally {
    }
    return dataTask;
}

#pragma mark - Post请求 Body

- (NSURLSessionDataTask *)postBodyRequest:(NSString *)url
                               parameters:(NSDictionary *)parameter
                             successBlock:(NetworkRequestSuccessBlock)successBlock
                             failureBlock:(NetworkRequestFailureBlock)failureBlock {
    
    WS(weakSelf);
    AFHTTPSessionManager *manager = [self getSessionManger];
    NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:url parameters:nil error:nil];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    NSDictionary *parameters = [[RequestParams share] parameterSortWithDictionary:parameter];
    NSLog(@"\n==>>>>url==%@\nparameters==%@",url,[parameters mj_JSONString]);
    // 设置body
    NSString *parseParam = parameters.mj_JSONString;
    NSData *postData = [parseParam dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:postData];
    request.timeoutInterval= 60;
    
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (error) {
            [weakSelf.requests removeObject:weakSelf.bodyTask];
            RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:weakSelf.bodyTask];
            [weakSelf.requestInfo removeObject:infoModel];
            
            if (failureBlock) {
                failureBlock(error,infoModel);
            }
        } else {
            [weakSelf.requests removeObject:weakSelf.bodyTask];
            RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:weakSelf.bodyTask];
            [weakSelf.requestInfo removeObject:infoModel];
            
            if (successBlock) {
                successBlock(responseObject,infoModel);
            }
        }
    }];
    [dataTask resume];
    
    self.bodyTask = dataTask;
    [self.requests addObject:self.bodyTask];
    // ：由于ios7系统给NSURLSessionTask添加类目属性会崩溃，所以改用此方法
    [self addToArrayWithNewTask:self.bodyTask url:url info:parameters];
    
    return dataTask;
}


#pragma mark - UploadFile请求 文件
- (NSURLSessionDataTask *)uploadFileWithUrl:(NSString *)url
                                 parameters:(NSDictionary *)parameter
                                  fileNames:(NSArray *)fileNames
                                      files:(NSArray *)files
                               successBlock:(NetworkRequestSuccessBlock)successBlock
                               failureBlock:(NetworkRequestFailureBlock)failureBlock {
    WS(weakSelf)
    AFHTTPSessionManager *sessionManager = [self getSessionManger];
    NSTimeInterval timeIntervals = 0;
    if ([files count] >= 3) {
        timeIntervals = ([files count] / 3  + 1) * kTimeoutInterval;
    }else
        timeIntervals = kTimeoutInterval;
    sessionManager.requestSerializer.timeoutInterval = timeIntervals;
    NSDictionary *parameters = [[RequestParams share] parameterSortWithDictionary:parameter];
    NSLog(@"\n上传图片==>>>>url==%@\nparameters==%@",url,[parameters mj_JSONString]);
    NSURLSessionDataTask *dataTask = [sessionManager POST:url parameters:parameters headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        for (NSInteger i = 0; i < [files count]; i++) {
            [formData appendPartWithFileData:files[i] name:@"file" fileName:fileNames[i] mimeType:@"application/octet-stream"];
        }
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        //：将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        
        //：先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        if (successBlock) {
            successBlock(responseObject,infoModel);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //：将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        //：先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        if (failureBlock) {
            failureBlock(error,infoModel);
        }
    }];
    
    //：将请求加入请求数组中
    [self.requests addObject:dataTask];
    
    // ：由于ios7系统给NSURLSessionTask添加类目属性会崩溃，所以改用此方法
    [self addToArrayWithNewTask:dataTask url:url info:parameters];
    
    return dataTask;
}

#pragma mark - UploadFile请求 压缩文件
- (NSURLSessionDataTask *)uploadImageZipWithUrl:(NSString *)url
                                     parameters:(NSDictionary *)parameter
                                       progress:(ProgressBlock)uploadProgress
                                  imagesZipPath:(NSURL *)imagesZipPath
                                   successBlock:(NetworkRequestSuccessBlock)successBlock
                                   failureBlock:(NetworkRequestFailureBlock)failureBlock {
    WS(weakSelf)
    AFHTTPSessionManager *sessionManager = [self getSessionManger];
    sessionManager.requestSerializer.timeoutInterval = 120;
    NSDictionary *parameters = [[RequestParams share] parameterSortWithDictionary:parameter];
    NSLog(@"\n上传zip文件==>>>>url==%@\nparameters==%@",url,parameters);
    NSURLSessionDataTask *dataTask = [sessionManager POST:url parameters:parameters headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        [formData appendPartWithFileURL:imagesZipPath name:@"file" fileName:@"file.zip" mimeType:@"application/zip" error:nil];
    } progress:uploadProgress success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        //：将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        
        //：先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        if (successBlock) {
            successBlock(responseObject,infoModel);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //：将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        //：先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [weakSelf getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        if (failureBlock) {
            failureBlock(error,infoModel);
        }
    }];
    //：将请求加入请求数组中
    [self.requests addObject:dataTask];
    
    // ：由于ios7系统给NSURLSessionTask添加类目属性会崩溃，所以改用此方法
    [self addToArrayWithNewTask:dataTask url:url info:parameters];
    
    return dataTask;
}


#pragma mark - UploadFile请求 视频文件
- (NSURLSessionDataTask *)uploadVideoWithUrl:(NSString *)url
                                  parameters:(NSDictionary *)parameter
                                   videoPath:(NSURL *)videoPath
                                successBlock:(NetworkRequestSuccessBlock)successBlock
                                failureBlock:(NetworkRequestFailureBlock)failureBlock {
    WS(weakSelf)
    AFHTTPSessionManager *sessionManager = [self getSessionManger];
    sessionManager.requestSerializer.timeoutInterval = kTimeoutInterval;
    NSDictionary *parameters = [[RequestParams share] parameterSortWithDictionary:parameter];
    NSLog(@"\n上传视频文件==>>>>url==%@\nvideoPath==%@\nparameters==%@",url,videoPath,parameters);
    NSURLSessionDataTask *dataTask = [sessionManager POST:url parameters:parameters headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        [formData appendPartWithFileURL:videoPath name:@"" fileName:@"" mimeType:@"mpeg4/mov" error:nil];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        NSLog(@"%@",uploadProgress);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        //：将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        
        //：先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [self getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        if (successBlock) {
            successBlock(responseObject,infoModel);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //：将请求从请求数组中移除
        [weakSelf.requests removeObject:task];
        //：先获取对应的model对象，再从数组中移除对应的model
        RequestInfoModel *infoModel = [self getInfoModelWithTask:task];
        [weakSelf.requestInfo removeObject:infoModel];
        
        NSLog(@"%@",error);
        if (failureBlock) {
            failureBlock(error,infoModel);
        }
    }];
    //：将请求加入请求数组中
    [self.requests addObject:dataTask];
    
    // ：由于ios7系统给NSURLSessionTask添加类目属性会崩溃，所以改用此方法
    [self addToArrayWithNewTask:dataTask url:url info:parameters];
    
    return dataTask;
}

#pragma mark - downloadFile请求 
- (NSURLSessionDownloadTask *)downloadFileWithUrl:(NSString *)strUrl
                                    localSavePath:(NSString *)savePath
                                         progress:(ProgressBlock)progressBlock
                                     successBlock:(NetworkRequestSuccessBlock)successBlock
                                     failureBlock:(NetworkRequestFailureBlock)failureBlock {
    
    //1.创建管理者对象
    AFHTTPSessionManager *manager = [self getSessionManger];
    //2.确定请求的URL地址
    NSURL *url = [NSURL URLWithString:strUrl];
    //3.创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //下载任务
    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
//        //打印下下载进度
//        NSString *strProgress = [NSString stringWithFormat:@"%lf",1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount];
//        NSLog(@"下载进度%@",strProgress);
        if (progressBlock) {
            progressBlock(downloadProgress);
        }
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        //默认下载地址
        NSLog(@"默认下载地址:%@",targetPath);
        
        if (ValidStr(savePath)) {
            //设置下载路径，通过沙盒获取缓存地址，最后返回NSURL对象
            return [NSURL fileURLWithPath:savePath];
        } else {
            return targetPath;
        }
        //NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        //下载完成调用的方法
        NSLog(@"下载完成：filePath = %@",filePath);
        
        if (error) {
            if (failureBlock) {
                failureBlock(error, [RequestInfoModel new]);
            }
        } else {
            if (successBlock) {
                successBlock(response,[RequestInfoModel new]);
            }
        }
    }];
    //开始启动任务
    [downloadTask resume];
    return downloadTask;
}



#pragma mark - Private Method
#pragma mark - 取消网络请求（全部 或者 单个）
- (void)cancelNetworkRequest {
    //遍历requests集合，移除所有request
    for (NSURLSessionTask *taskTemp in self.requests) {
        if (taskTemp.state == NSURLSessionTaskStateRunning) {
            [taskTemp cancel]; //cancel 之后会走失败block，而失败block里已经将该task移除了，所以这里不需要移除
        }
    }
}

//取消单个网络请求
- (void)cancelNetworkRequestWithTask:(NSURLSessionTask *)task {
    if (task.state == NSURLSessionTaskStateRunning) { //如果要取消的请求正在运行中，才取消
        for (NSURLSessionTask *taskTemp in self.requests) {
            if ([taskTemp isEqual:task]) {
                [task cancel]; //cancel 之后会走失败block，而失败block里已经将该task移除了，所以这里不需要移除
                return;
            }
        }
    } else{
//        NSLog(@"task并未运行，无需取消--->>>【%@】 ",task);
    }
}

// ：将请求相关数据添加到数组中
-(void) addToArrayWithNewTask:(NSURLSessionTask *)dataTask url:(NSString *)url info:(NSDictionary *)info {
    // ：由于ios7系统给NSURLSessionTask添加类目属性会崩溃，所以改用此方法
    RequestInfoModel *requestInfoModel = [[RequestInfoModel alloc]init];
    requestInfoModel.sessionTask = dataTask;
    requestInfoModel.url = url;
    requestInfoModel.requestParam = info;
    requestInfoModel.timeStamp = kSystemTimeStamp;
    
    @try {
        [self.requestInfo addObject:requestInfoModel];
    } @catch (NSException *exception) {
//        [[FSToastTool share] showHUDWithTitle:exception.description inView:kKeyWindow isPenetration:YES];
    } @finally {
        
    }
}

// ：根据task，从requestInfo数组中找到对应的model
- (RequestInfoModel *) getInfoModelWithTask:(NSURLSessionTask *)dataTask {
    RequestInfoModel *infoModel;
    for (RequestInfoModel *modelTemp in self.requestInfo) {
        if ([dataTask isEqual:modelTemp.sessionTask]) {//如果传入的task等于遍历的task，则退出循环
            infoModel = modelTemp;
            break;
        }
    }
    return infoModel;
}

#pragma mark - getter && setter
- (NSMutableArray *)requests {
    if (!_requests) {
        _requests = [NSMutableArray array];
    }
    return _requests;
}

- (NSMutableArray *)requestInfo {
    if (!_requestInfo) {
        _requestInfo = [NSMutableArray array];
    }
    return _requestInfo;
}

@end
